package com.utilcase.rabbitmq;

import com.rabbitmq.client.Channel;
import com.utilcase.domain.MessageLog;
import com.utilcase.enums.MessageStatus;
import com.utilcase.enums.OrderStatus;
import com.utilcase.service.MessageLogService;
import com.utilcase.service.OrdersService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.annotation.*;
import org.springframework.stereotype.Component;

import java.io.IOException;

/**
 * 普通队列消费者
 */
@Component
@RequiredArgsConstructor
@Slf4j
public class MessageConsumer {
    private final MessageLogService messageLogService;
    private final OrdersService ordersService;

    @RabbitHandler
    @RabbitListener(bindings = {
            @QueueBinding(
                    value = @Queue(value = "order_queue", arguments = {
                            @Argument(name = "x-dead-letter-exchange", value = "order_dlx_exchange"),//死信交换机
                            @Argument(name = "x-dead-letter-routing-key", value = "order.failed"),//死信路由key
                            @Argument(name = "x-message-ttl", value = "10000", type = "java.lang.Integer"),//消息过期时间
                            @Argument(name = "x-max-length", value = "5", type = "java.lang.Integer") //队列最大长度
                    }),//可以指定多种属性
                    exchange = @Exchange(value = "order_exchange"),
                    key = {"order.new"}
            )
    })
    public void receive(MessageLog receiveMsg, Channel channel, Message message) throws IOException {

        long deliveryTag = message.getMessageProperties().getDeliveryTag();
        log.info("order_queue队列接收到消息：{}，消息头信息：{}，消息头属性：{}", receiveMsg, deliveryTag, message.getMessageProperties());
        String orderId = receiveMsg.getMessageId();
        try {
            // 检查订单是否已经处理过 (幂等性处理)
            if (ordersService.checkOrderExists(Long.valueOf(orderId))) {
                // 订单已处理，手动ack
                channel.basicAck(deliveryTag, false);
                return;
            }
            // 模拟异常
//            int i = 1 / 0;
            // 处理业务逻辑，如库存扣减、会员信息处理、订单信息状态更新等
            ordersService.updateStatus(orderId, OrderStatus.COMPLETED);
            // 查找并更新消息表状态 （逻辑删除消息表消息）
            messageLogService.updateStatus(orderId, MessageStatus.PROCESSED);
            // 消费成功，手动ack
            channel.basicAck(deliveryTag, false);
            log.info("处理成功");

        } catch (Exception e) {
            ordersService.updateStatus(orderId, OrderStatus.FAILED);
            messageLogService.updateStatus(orderId, MessageStatus.FAILED);
            // 处理异常，记录日志等
            // 可以在这里决定是否重新抛出异常，让RabbitMQ进行重试
            // 或者直接nack拒绝消息，消息会进入死信队列
            /**
             * 交于死信队列处理
             * deliveryTag– 收到的AMQP的标签。 AMQP.Basic.GetOk or AMQP.Basic.Deliver。
             * multiple– true 拒绝所有消息；false表示仅拒绝指定标签消息。
             * requeue– true 重新入队列，false 拒绝消息/死信。
             */
            log.info("业务异常，死信处理");
            channel.basicNack(deliveryTag, false, false); // 拒绝消息
            // 或者下述方法
//            channel.basicReject(deliveryTag, false); // 拒绝消息
        }
    }
}